// 文件路径: dbms/cluster/PeerNodeClient.java
package com.dbms.cluster;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

/**
 * 集群节点客户端 (Peer-to-Peer Client)。
 * 这个类提供了一个静态方法，负责与集群中的另一个节点（Peer）建立连接，
 * 并向其发送一个请求（ClusterRequest），然后等待并接收响应（ClusterResponse）。
 */
public class PeerNodeClient {

    /**
     * 向目标节点发送一个集群请求，并返回其响应。
     * 这是一个阻塞操作，会等待直到收到响应或发生错误。
     *
     * @param targetNode 目标节点的信息（包含IP地址和端口）。
     * @param request    要发送的请求对象 (ClusterRequest)。
     * @return 从目标节点返回的响应对象 (ClusterResponse)。
     * @throws Exception 如果网络通信失败、连接被拒绝或序列化/反序列化出错。
     */
    public static ClusterResponse sendRequest(NodeInfo targetNode, ClusterRequest request) throws Exception {
        // 使用 try-with-resources 语句可以确保 Socket 和相关的流在使用完毕后被自动关闭，
        // 无论代码是正常执行还是抛出异常，从而避免资源泄漏。
        try (
                // 1. 根据目标节点信息，创建一个新的Socket连接。
                Socket socket = new Socket(targetNode.getHost(), targetNode.getPort());
                // 2. 创建一个对象输出流，用于将Java对象序列化后写入Socket的输出流。
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                // 3. 创建一个对象输入流，用于从Socket的输入流中读取数据并反序列化成Java对象。
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream())
        ) {
            // 4. 将请求对象写入对象输出流。
            oos.writeObject(request);
            // 5. 刷新输出流，确保请求对象被立刻发送出去，而不是停留在缓冲区。
            oos.flush();

            // 6. 从对象输入流中读取响应对象。这个方法会阻塞，直到对方节点发回响应。
            //    读取到的对象需要强制类型转换为 ClusterResponse。
            return (ClusterResponse) ois.readObject();
        }
    }
}